package com.pku.ss.ui;

import java.lang.reflect.InvocationTargetException;




//import javax.swing.tree.DefaultMutableTreeNode;




import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

/**
 * 
 * @author Wangjie
 *
 */
public class ASTExplorer extends Composite {

	private Tree treeControl;
	private StyledText textControl;
	private StyledText errorsTextControl;
	private IProblem[] problems;
	private Color blue;
	private Color red;
	

	
	private org.eclipse.jdt.internal.core.CompilationUnit _compilationUnit=null;

	public void initComponents() {

	}

	public ASTExplorer(Composite parent, int style,org.eclipse.jdt.internal.core.CompilationUnit compilationUnit) {
		super(parent, style);
		_compilationUnit=compilationUnit;
		this.problems = new IProblem[0];
		this.blue = getDisplay().getSystemColor(SWT.COLOR_BLUE);
		this.red = getDisplay().getSystemColor(SWT.COLOR_RED);

		GridLayout gridLayout = new GridLayout();
		super.setLayout(gridLayout);
		
		Composite composite = new Composite(this, SWT.NONE);
		gridLayout = new GridLayout();
		gridLayout.numColumns = 3;
		composite.setLayout(gridLayout);
		composite.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
		
		
		SashForm sashFormHorizontal = new SashForm(this,
				SWT.HORIZONTAL);
		sashFormHorizontal.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
				| GridData.GRAB_VERTICAL | GridData.HORIZONTAL_ALIGN_FILL
				| GridData.VERTICAL_ALIGN_FILL));

		this.treeControl = new Tree(sashFormHorizontal, SWT.ARROW_UP | SWT.SINGLE);
		this.treeControl.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
				| GridData.VERTICAL_ALIGN_FILL));
		this.treeControl.addSelectionListener(new SelectionAdapter() {
			public void widgetSelected(SelectionEvent e) {
				// first reset any previous selections
				StyleRange styleRange = new StyleRange();
				styleRange.start = 0;
				styleRange.length = textControl.getCharCount();
				textControl.setStyleRange(styleRange);

				// select text
				int startSelection = -1;
				Tree tree = (Tree) e.widget;
				
				TreeItem[] items = tree.getSelection();
				for (int i = 0; i < items.length; ++i) {
					ASTNode node = (ASTNode) items[i]
							.getData(ASTExplorerVisitor.NODE);
					if (node != null) {
						styleRange = createRange(node.getStartPosition(), node
								.getLength(), blue);
						textControl.setStyleRange(styleRange);
						if (startSelection < 0
								|| styleRange.start < startSelection)
							startSelection = styleRange.start;
					}
				}
				if (startSelection >= 0)
					textControl.setSelection(startSelection);

				// select errors
				for (int i = 0; i < problems.length; ++i) {
					IProblem problem = problems[i];
					// String msg = problem.getMessage();
					styleRange = createRange(problem.getSourceStart(), problem
							.getSourceEnd()
							- problem.getSourceStart() + 1, red);
					textControl.setStyleRange(styleRange);
				}
			}
		});

		this.textControl = new StyledText(sashFormHorizontal, SWT.BORDER
				| SWT.READ_ONLY | SWT.H_SCROLL | SWT.V_SCROLL);
		this.textControl.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
				|GridData.HORIZONTAL_ALIGN_FILL	));

		/*this.errorsTextControl = new StyledText(this,
				SWT.BORDER | SWT.READ_ONLY | SWT.H_SCROLL | SWT.V_SCROLL);
		this.errorsTextControl.setLayoutData(new GridData(
				GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));*/

		
	}

	static private StyleRange createRange(int start, int length, Color color) {
		StyleRange styleRange = new StyleRange();
		styleRange.start = start;
		styleRange.length = length;
		styleRange.fontStyle = SWT.BOLD;
		styleRange.foreground = color;
		return styleRange;
	}

	
	private void reset() {
		// this.fileTreeControl.removeAll();
		this.treeControl.removeAll();
		this.textControl.setText("");
		this.errorsTextControl.setText("");
		this.problems = new IProblem[0];
	}

	private void SetFile(final String path) throws InterruptedException,
			InvocationTargetException {
		reset();
		ProgressMonitorDialog dialog = new ProgressMonitorDialog(getShell());
		dialog.run(true, true, new IRunnableWithProgress() {
			public void run(final IProgressMonitor monitor)
					throws InvocationTargetException {
				try {
					
					final CompilationUnit node = _compilationUnit.reconcile(AST.JLS4, true, null,null);
					final String text =_compilationUnit.getSource();
					// System.out.println("============"+node);
					if (monitor.isCanceled())
						return;
					getDisplay().syncExec(new Runnable() {
						public void run() {
							ASTVisitor visitor = new ASTExplorerVisitor(
									treeControl, monitor);
							node.accept(visitor);
							if (!monitor.isCanceled()) {
								textControl.setText(text);
								IProblem[] errors = node.getProblems();
								if (errors != null && errors.length > 0) {
									problems = errors;
									int startSelection = -1;
									StringBuffer msg = new StringBuffer();
									for (int i = 0; i < problems.length; ++i) {
										IProblem problem = problems[i];
										StyleRange errorRange = createRange(
												problem.getSourceStart(),
												problem.getSourceEnd()
														- problem
																.getSourceStart()
														+ 1, red);
										textControl.setStyleRange(errorRange);
										if (startSelection < 0
												|| errorRange.start < startSelection)
											startSelection = errorRange.start;

										String message = problem.getMessage()
												+ " line: "
												+ problem.getSourceLineNumber();
										msg.append(message);
										msg.append("\n");
									}
									if (startSelection >= 0)
										textControl
												.setSelection(startSelection);

									if (msg.length() > 0)
										errorsTextControl.setText(msg
												.toString());
								}
							}
						}
					});
				} catch (JavaModelException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
	}

	// do not allow layout modifications
	public void setLayout(Layout layout) {
	}

	/*private void showError(Throwable e) {
		MessageBox msgBox = new MessageBox(addressControl.getShell(),
				SWT.APPLICATION_MODAL | SWT.OK | SWT.ICON_ERROR);
		msgBox.setText("AST Explorer Error");
		String msg = e.getMessage();
		if (null == msg)
			msg = e.toString();

		msgBox.setMessage(msg);
		msgBox.open();
	}*/
	public static void Init(final org.eclipse.jdt.internal.core.CompilationUnit compilationUnit){
		 Display.getDefault().asyncExec(new Runnable(){
		     @Override
		     public void run() {
		    	 Shell shell = new Shell();
		    	 shell.setText("While Box Testing");
		 		shell.setLayout(new FillLayout());
		 		TabFolder tabFolder = new TabFolder(shell, SWT.NONE);

		 		TabItem astTabItem = new TabItem(tabFolder, SWT.NONE);
		 		astTabItem.setText("AST");
		 		ASTExplorer astExplorer = new ASTExplorer(tabFolder, SWT.NONE,compilationUnit);
		 		astTabItem.setControl(astExplorer);
		 		final Point minimum = shell.computeSize(SWT.DEFAULT, SWT.DEFAULT, true);
		 		shell.addControlListener(new ControlAdapter() {
		 			public void controlResized(ControlEvent e) {
		 				Shell shell = (Shell) e.widget;
		 				Point size = shell.getSize();
		 				boolean change = false;
		 				if (size.x < minimum.x) {
		 					size.x = minimum.x;
		 					change = true;
		 				}
		 				if (size.y < minimum.y) {
		 					size.y = minimum.y;
		 					change = true;
		 				}
		 				if (change)
		 					shell.setSize(size);
		 			}
		 		});
		 		shell.open();
		 		try {
					astExplorer.SetFile("");
				} catch (InterruptedException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				} catch (InvocationTargetException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
		     }
		    });
		
	}
	
	@Override
	protected void checkSubclass() {
		// Disable the check that prevents subclassing of SWT components
	}

}
